Just for fun - 解数独


所有跟贴·加跟贴·新语丝读书论坛

送交者: qtl 于 2009-06-21, 01:45:11:

解medium及以下级的一次可以出结果,hard级的一般要试一次,即从二选一的结果中挑一个作为已知值,very hard级要试两三次。除了试解,我现在还没有想出什么简单的好法子。

#include<iostream>
#include<fstream>
#include<iomanip>
using namespace std;

const int test[10]={511,1,2,4,8,16,32,64,128,256};

void sub(int &a, int b){
int i;
for(i=1; i<10; ++i)
if(a&test[i] && b&test[i])
a-=test[i];
}


int main(int argc, char* argv[]){
if(argc!=2){
cout<<"Usage: sudoku in-file"<<endl;
cout<<" example file contents:"<<endl;
cout<<" 0 5 0 0 1 4 0 3 0"<<endl;
cout<<" 0 0 2 0 7 0 0 4 0"<<endl;
cout<<" 0 1 0 0 0 8 0 0 0"<<endl;
cout<<" 0 2 9 0 4 5 3 0 0"<<endl;
cout<<" 0 0 7 0 8 0 6 0 0"<<endl;
cout<<" 0 0 1 3 6 0 5 2 0"<<endl;
cout<<" 0 0 0 4 0 0 0 6 0"<<endl;
cout<<" 0 7 0 0 2 0 8 0 0"<<endl;
cout<<" 0 9 0 8 5 0 0 1 0"<<endl;
cout<<" Position of 0s are to be filled."<<endl;
return 1;
}

ifstream fin(argv[1]);
int pro[10][10], ref[10][10], i,j,k,t,nz(0),lrb,lre,lcb,lce,m,n,old;

cout<<"Below is your problem:"<<endl;
for(i=1; i<10; ++i){
for(j=1; j<10; ++j){
fin>>pro[i][j];
if(pro[i][j]==0){
    ++nz;
    ref[i][j]=test[0];
}else{
    ref[i][j]=test[pro[i][j]];
}
cout<<setw(5)<<pro[i][j];
}
cout<<endl;
}

old=nz;
while(nz>0){
for(i=1; i<10; ++i)
for(j=1; j<10; ++j){
    if(pro[i][j]==0){
     //Any filled row number?
     for(k=1; k<10; ++k){
     t=pro[k][j];
     if(t>0)if(test[t]&ref[i][j])ref[i][j]-=test[t];
     }
     //Column
     for(k=1; k<10; ++k){
     t=pro[i][k];
     if(t>0)if(test[t]&ref[i][j])ref[i][j]-=test[t];
     }
     //Local square
     if(i>6){
     lrb=7;
     lre=10;
     }else if(i>3){
     lrb=4;
     lre=7;
     }else{
     lrb=1;
     lre=4;
     }
     if(j>6){
     lcb=7;
     lce=10;
     }else if(j>3){
     lcb=4;
     lce=7;
     }else{
     lcb=1;
     lce=4;
     }
     for(m=lrb; m<lre; ++m)
     for(n=lcb; n<lce; ++n){
     t=pro[m][n];
     if(t!=0)if(test[t]&ref[i][j])ref[i][j]-=test[t];
     }
     //Advanced
     if(pro[i][j]==0){
     //check if any unique number of multiple choices in this row
     t=ref[i][j];
     for(k=1;k<10;++k){
     if(k==i)continue;
     sub(t,ref[k][j]);
     }
     if(t>0)ref[i][j]=t;
     //column
     t=ref[i][j];
     for(k=1;k<10;++k){
     if(k==j)continue;
     sub(t,ref[i][k]);
     }
     if(t>0)ref[i][j]=t;
     //local square
     t=ref[i][j];
     for(m=lrb; m<lre; ++m)
     for(n=lcb; n<lce; ++n){
        if(m==i && n==j)continue;
        sub(t,ref[m][n]);
     }
     if(t>0)ref[i][j]=t;
     }

     //Check if can fill now
     t=0;
     for(k=1; k<10; ++k)
     if(ref[i][j]&test[k]){
     ++t;
     m=k;
     }
     if(t==1){
     pro[i][j]=m;
     --nz;
     }
    }
}
if(old==nz){
cout<<endl<<"Algorithm need to be improved."<<endl<<endl;
break;
}
old=nz;
}

cout<<endl<<"Answer up to now:"<<endl;
for(i=1; i<10; ++i){
for(j=1; j<10; ++j){
if(pro[i][j]>0){
    cout<<pro[i][j];
    if(j<9)cout<<" ";
}else{
    t=0;
    for(k=1; k<10; ++k)
     if(test[k]&ref[i][j]){
     cout<<k;
     ++t;
     }
    if(j<9)for(k=0; k<8-t; ++k)cout<<' ';
}
}
cout<<endl;
}

return 0;
}




所有跟贴:


加跟贴

笔名: 密码: 注册笔名请按这里

标题:

内容: (BBCode使用说明